#include "./include/M_printModule@windows.h"
#include "../Semaphore/include/Semaphore_t.h"
#include <iostream>
#include <iomanip>
#include <string.h>

using namespace std;


#define     LOG
#define     NOW_THREAD_OUTLINSE    5

///////////////////////////////////////////////////////////////////////////////
///////////////////////  全局变量  /////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

/*
 * 定义控制台互斥信号量
 */
Semaphore_t console_mutex=1;

/*
 * 定义用于 windows 控制台输出的全局变量
 */
HANDLE out_h;   // 标准输出句柄
CONSOLE_SCREEN_BUFFER_INFO screen_bInfo;  // 控制台屏幕缓冲区信息
COORD MFQ_position[MFQ_MAXSIZE+1]={};
COORD last_thread_position;
COORD now_thread_position;
COORD next_thread_position;
COORD log_position; 


void initConsole(int cols, int lines)
{
    char str[50]={};
    sprintf(str,"mode con cols=%d lines=%d",cols,lines);
    system(str);
    out_h=GetStdHandle(STD_OUTPUT_HANDLE);

    P(&console_mutex);
    cout << endl ;
    COORD cursor;
    snapshotCOORD(&cursor);

    // 打印 MFQ 头部
    cursor.X = 4;
    for(int i=MFQ_MAXSIZE; i>0; i--) {
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "| " << i << " |" ;
        updateCOORD(&MFQ_position[i],cursor.X+5,cursor.Y);
        cursor.Y -= 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "+---+" ;
        cursor.Y += 2;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "+---+" ;
        cursor.Y += 1;
    }

    // 打印运行信息
    cursor.Y += 2;
    SetConsoleCursorPosition(out_h,cursor);
    cout << "Last run thread: ";
    updateCOORD(&last_thread_position,cursor.X+17,cursor.Y);
    cursor.Y += 1;
    SetConsoleCursorPosition(out_h,cursor);
    cout << "next run thread: ";
    updateCOORD(&next_thread_position,cursor.X+17,cursor.Y);
    cursor.Y +=2 ;
    SetConsoleCursorPosition(out_h,cursor);
    cout << "current running thread: " ;
    updateCOORD(&now_thread_position, 0, cursor.Y);
    now_thread_position.X = 4;
    now_thread_position.Y += 1;

    log_position.X=4;
    log_position.Y=now_thread_position.Y+NOW_THREAD_OUTLINSE+3;

    hideCursor(); // 隐藏光标
    V(&console_mutex);
}

void printLastThread()
{
    extern TCB_t* pTCBs[MAX_THREAD_SIZE+1];
    extern int last_thread;
    if(0<=last_thread) {
        TCB_t* pTCB=pTCBs[last_thread];
        COORD cursor;
        copyCOORD(&cursor,&last_thread_position);
        P(&console_mutex);
        SetConsoleCursorPosition(out_h,cursor);
        cout << pTCB->name ;
        cursor.X += 2;
        SetConsoleCursorPosition(out_h,cursor);
        if(pTCB->isDeprived) {
            // cout << "  [ be deprived, priority=" << pTCB->priority <<" ]";
            cout << "  [ be deprived ]";
        } else {
            cout << "  [ run out ]     ";
        }
        V(&console_mutex);
    }
}
void printNowThread()
{
    extern TCB_t* pActiveTCB;
    if(pActiveTCB) {
        COORD cursor;
        copyCOORD(&cursor,&now_thread_position);
        cursor.X += 2;
        P(&console_mutex);
        SetConsoleCursorPosition(out_h,cursor);
        cout << "* thread <" << pActiveTCB->name << "> is runing......";
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "* priority: " << pActiveTCB->priority;
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "* time slice: " << pActiveTCB->time_slice << " " ;
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "* run time: " << pActiveTCB->run_time << "  ";
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "* total time: " << pActiveTCB->total_time << " ";
        cursor.Y += 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout.setf(ios::left);
        cout << setw(60) << setfill(' ') << "* interrupt: " << endl;
        V(&console_mutex);
    }
}
void printNextThread()
{
    extern MFQ_t* pMFQ;
    ElemNode* pNode=top(pMFQ);
    if(pNode) {
        TCB_t* pTCB=(TCB_t *)(pNode->pEelm);
        if(pTCB) {
            COORD cursor;
            copyCOORD(&cursor,&next_thread_position);
            P(&console_mutex);
            SetConsoleCursorPosition(out_h,cursor);
            cout << pTCB->name << "   [ priority=" << pNode->nid << " ]";
            V(&console_mutex);
        }
    } 
}
void printInterrupt()
{
    COORD cursor;
    copyCOORD(&cursor,&now_thread_position);
    cursor.Y += 5;
    cursor.X += (4+11);
    P(&console_mutex);
    SetConsoleCursorPosition(out_h,cursor);
    cout << "clock" ;
    V(&console_mutex);
}

void printElemNode(ElemNode *pNode)
{
    if(pNode) {
        TCB_t *pTCB=(TCB_t *)(pNode->pEelm);
        cout << "--->| " << pTCB->name << " |";
        COORD cursor;
        snapshotCOORD(&cursor);
        cursor.X -= 5;
        cursor.Y -= 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "+---+";
        cursor.Y += 2;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "+---+";
    }  else {
        cout << "         " ;
        COORD cursor;
        snapshotCOORD(&cursor);
        cursor.X -= 5;
        cursor.Y -= 1;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "     ";
        cursor.Y += 2;
        SetConsoleCursorPosition(out_h,cursor);
        cout << "     ";        
    }  
}

void printQueueLink(QueueLink *pQueue)
{
    if(pQueue) {
        ElemNode *pNode=pQueue->qHead;
        COORD cursor;
        for(int i=0; i<MAX_THREAD_SIZE ;i++) {
            printElemNode(pNode);
            snapshotCOORD(&cursor);
            cursor.Y -= 1;
            SetConsoleCursorPosition(out_h,cursor);
            pNode = pNode ? pNode->next : NULL;
        }
    }
}
void showMFQ(MFQ_t *pMFQ)
{
    if(pMFQ) {
        P(&console_mutex);
        for(int i=pMFQ->size; i>0; i--) {
            SetConsoleCursorPosition(out_h,MFQ_position[i]);
            printQueueLink(pMFQ->QueueTable[i]);
        }
        V(&console_mutex);
    }
}


void hideCursor()
{
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(out_h,&cursorInfo);
    cursorInfo.bVisible=FALSE;
    SetConsoleCursorInfo(out_h,&cursorInfo);
}
void showCursor()
{
    CONSOLE_CURSOR_INFO cursorInfo;
    GetConsoleCursorInfo(out_h,&cursorInfo);
    cursorInfo.bVisible=TRUE;
    SetConsoleCursorInfo(out_h,&cursorInfo);
}

void snapshotCOORD(COORD *pos)
{
    if(pos) {
        GetConsoleScreenBufferInfo(out_h, &screen_bInfo);
        copyCOORD(pos, &screen_bInfo.dwCursorPosition);
    }
}
void updateCOORD(COORD *pos, int x, int y)
{
    if(pos && 0<=x && 0<=y) {
        pos->X=x;
        pos->Y=y;
    }
}
void copyCOORD(COORD *dst, const COORD *src)
{
    if(dst && src) {
        dst->X=src->X;
        dst->Y=src->Y;
    }
}

